#pragma once
#include <iostream>
#include <pthread.h>
#include <queue>


typedef void (*Handler)(int data);

class QueueData{
  public:
    QueueData(){

    }
    QueueData(int d,Handler h){
      data_=d;
      handler_=h;
    }
    ~QueueData(){

    }

    //提供给线程调用
    void Run(){    
      handler_(data_);
    }

  private:
    int data_;
    Handler handler_;  //保存处理数据的方法
};

class ThreadPool{
  public:
    ThreadPool(int tc){
      pthread_mutex_init(&lock_,NULL);
      pthread_cond_init(&cons_cond_,NULL);
      pthread_cond_init(&prod_cond_,NULL);

      thread_count_=tc;
      capacity_=10;
      exit_flag_=0;
    }

    ~ThreadPool(){
      pthread_mutex_destroy(&lock_);
      pthread_cond_destroy(&cons_cond_);
      pthread_cond_destroy(&prod_cond_);
    }

    static void* thread_pool_start(void* arg){
      pthread_detach(pthread_self());
      ThreadPool* tp=(ThreadPool*)arg;
      while(1){
        pthread_mutex_lock(&tp->lock_);
        while(tp->que_.empty()){
          if(tp->exit_flag_){
            pthread_mutex_unlock(&tp->lock_);
            tp->thread_count_--;
             pthread_exit(NULL);
          }
          pthread_cond_wait(&tp->cons_cond_,&tp->lock_);
        }

        QueueData qd;
        tp->Pop(&qd);

        pthread_mutex_unlock(&tp->lock_);
        pthread_cond_signal(&tp->prod_cond_);
        qd.Run();
      }
      return NULL;
    }

    //初始化线程池
    int OnInit(){
      int exit_thread_count=0;
      for(int i=0;i<thread_count_;i++){
        pthread_t tid;
        int ret=pthread_create(&tid,NULL,thread_pool_start,(void*)this);
        if(ret<0){
          exit_thread_count++;
        }
      }

      return thread_count_-=exit_thread_count;
      }


    void Push(const QueueData& qd){
      pthread_mutex_lock(&lock_);
      if(exit_flag_){
        pthread_mutex_unlock(&lock_);
        return;
      }
      while(que_.size()>=capacity_){
        pthread_cond_wait(&prod_cond_,&lock_);
      }
      que_.push(qd);
      pthread_mutex_unlock(&lock_);
      pthread_cond_signal(&cons_cond_);
    }

    void Pop(QueueData* qd){
      *qd=que_.front();
      que_.pop();
    }

    void ThreadPoolExit(){
      exit_flag_=1;
      while(thread_count_>0){
        pthread_cond_signal(&cons_cond_);
      }
    }

  private:
    std::queue<QueueData> que_;
    pthread_mutex_t lock_;
    pthread_cond_t cons_cond_;
    pthread_cond_t prod_cond_;

    size_t capacity_;
    int thread_count_;
    int exit_flag_;
};




